<template>
    <Picker
        ref="picker"
        :data="pickData"
        :default-index="pickIndex"
        :show-toolbar="true"
        :mask-click="true"
        :link="true"
        :title="title"
        :visible.sync="visible"
        @cancel="doCancel"
        @change="doChange"
        @confirm="doConfirm"
    />
</template>

<script>
import Picker from 'vue-pickers';

/**
 * 日期仿IOS控件
 */
export default {
    name: 'DatePicker',
    components: { Picker },
    model: { prop: 'show', event: 'updateStatus' },
    props: {
        // 是否显示
        show: { type: Boolean, default: false },
        // 最小日期
        minDate: { type: String, default: '2000-01-01' },
        // 最大日期
        maxDate: { type: String, default: '3000-12-31' },
        // 标题
        title: { type: String, default: '' },
        // 当前日期，支持文本
        currentDate: {
            type: String,
            default() {
                return this.$utils.formatDateTime(new Date(), 'yyyy-MM-dd');
            },
        },
    },
    data() {
        return {
            visible: false,
            // 因为改变数组也导致change事件，只好设置避免死锁
            disabledChangeHandle: true,
            date: { inited: false, min: null, max: null, current: null },
            year: { nums: [], index: 0 },
            month: { nums: [], index: 0 },
            day: { nums: [], index: 0 },
        };
    },
    computed: {
        pickData() {
            return [
                this.getItemFromArr(this.year.nums),
                this.getItemFromArr(this.month.nums),
                this.getItemFromArr(this.day.nums),
            ];
        },
        pickIndex() {
            return [this.year.index, this.month.index, this.day.index];
        },
    },
    watch: {
        show: {
            handler(val) {
                this.visible = val;
                this.date.inited = false;
                if (val) {
                    this.initYear();
                    this.setDefaultIndex('year');
                }
            },
        },
        visible(val) {
            if (val !== this.show) {
                this.$emit('updateStatus', val);
            }
        },
        minDate() {
            this.date.inited = false;
            this.initYear();
        },
        maxDate() {
            this.date.inited = false;
            this.initYear();
        },
        currentDate() {
            this.date.inited = false;
            this.initYear();
        },
    },
    methods: {
        doConfirm(val) {
            const date = this.$utils.getDateByData(val.map((d) => d.value).join('-'));
            this.$emit('on-enter', date);
        },
        doCancel() {},
        doChange(val) {
            if (this.disabledChangeHandle) {
                setTimeout(() => {
                    this.disabledChangeHandle = false;
                }, 10);
                return;
            }
            if (val[0] && val[0].value) {
                this.year.index = this.year.nums.indexOf(val[0].value);
            }
            if (val[1] && val[1].value) {
                this.month.index = this.month.nums.indexOf(val[1].value);
            }
            if (val[2] && val[2].value) {
                this.day.index = this.day.nums.indexOf(val[2].value);
            }
            this.initYear();
            this.$emit(
                'on-change',
                this.$utils.getDateByData(val.map((d) => d.value).join('-'))
            );
        },
        isLeapYear: (year) => {
            return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
        },
        getDateRange() {
            if (!this.date.inited) {
                this.date.min = this.$utils.getDateByData(this.minDate);
                this.date.max = this.$utils.getDateByData(this.maxDate);
                this.date.current =
                    this.$utils.getDateByData(this.currentDate) || new Date();
            }
            this.date.current.getTime() > this.date.max.getTime()
                ? (this.date.current = this.date.max)
                : null;
            this.date.current.getTime() < this.date.min.getTime()
                ? (this.date.current = this.date.min)
                : null;
            this.date.inited = true;
            return this.date;
        },
        getRange(min, max) {
            let arr = [];
            for (let i = min; i < max + 1; i++) {
                arr.push(i);
            }
            return arr;
        },
        getDays(year, month) {
            switch (month) {
                case 2:
                    return this.isLeapYear(year) ? 29 : 28;
                case 4:
                case 6:
                case 9:
                case 11:
                    return 30;
                default:
                    return 31;
            }
        },
        initYear() {
            this.disabledChangeHandle = true;
            const date = this.getDateRange();
            this.year.nums = this.getRange(
                date.min.getFullYear(),
                date.max.getFullYear()
            );
            if (this.year.index > this.year.nums.length - 1) {
                this.year.index = this.year.nums.length - 1;
            }
            this.initMonth();
        },
        initMonth() {
            const date = this.getDateRange();
            let year = this.year.nums[this.year.index];
            let min = year === date.min.getFullYear() ? date.min.getMonth() + 1 : 1;
            let max = year === date.max.getFullYear() ? date.max.getMonth() + 1 : 12;
            this.month.nums = this.getRange(min, max);
            if (this.month.index > this.month.nums.length - 1) {
                this.month.index = this.month.nums.length - 1;
            }
            this.initDay();
        },
        initDay() {
            const date = this.getDateRange();
            let year = this.year.nums[this.year.index];
            let month = this.month.nums[this.month.index];
            let min =
                year === date.min.getFullYear() && date.min.getMonth() + 1 === month
                    ? date.min.getDate()
                    : 1;
            let max =
                year === date.max.getFullYear() && date.max.getMonth() + 1 === month
                    ? date.max.getDate()
                    : this.getDays(year, month);
            this.day.nums = this.getRange(min, max);
            if (this.day.index > this.day.nums.length - 1) {
                this.day.index = this.day.nums.length - 1;
            }
        },
        getItemFromArr(arr) {
            return arr.map((d) => {
                return { label: d, value: d };
            });
        },
        setDefaultIndex(type) {
            switch (type) {
                case 'year':
                    this.year.index = this.year.nums.indexOf(
                        this.date.current.getFullYear()
                    );
                    this.initMonth();
                    this.setDefaultIndex('month');
                    break;
                case 'month':
                    this.month.index = this.month.nums.indexOf(
                        this.date.current.getMonth() + 1
                    );
                    this.initDay();
                    this.setDefaultIndex('day');
                    break;
                case 'day':
                    this.day.index = this.day.nums.indexOf(this.date.current.getDate());
                    break;
            }
        },
    },
};
</script>

<style lang="less" scoped>
/deep/.header {
    margin-bottom: 20px;
}
/deep/.title {
    max-width: 100% !important;
    position: relative;
    top: 34px;
    color: #666;
    text-overflow: inherit !important;
    font-size: 12px !important;
}
</style>
